[Kinesis Video Streams] Raspberry Piでh.264エンコードをする3種類の方法
1 はじめに
Kinesis Video Streamsへ動画を送信する場合、メディア形式は、h.264又は、h.265である必要があります。
このため、GStreamerのパイプライン等、どこかの段階で、エンコードを組み込む必要があります。
今回は、Raspberry Pi で送信する場合に利用可能な、3種類のh.264エンコードについて確認してみました。
2 環境
確認に使用した環境は、Model 4B と Raspberry Piの公式カメラ V2です。
OSは、昨年9月の最新版(Raspbian GNU/Linux 10 (buster) 2019-09-26-raspbian-buster-full.img です。
$ cat /proc/cpuinfo | grep Revision Revision : c03112 $ lsb_release -a No LSB modules are available. Distributor ID: Raspbian Description: Raspbian GNU/Linux 10 (buster) Release: 10 Codename: buster $ uname -a Linux raspberrypi 4.19.75-v7l+ #1270 SMP Tue Sep 24 18:51:41 BST 2019 armv7l GNU/Linux
以降の作業は、環境変数で認証情報とリージョンを設定した状態で行っています。
export AWS_DEFAULT_REGION=ap-northeast-1 export AWS_ACCESS_KEY_ID=xxxxxxxxxxxxxx export AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxx
また、デバイスはdevice=/dev/video0(v4l2srcでのデフォルト)で認識されてます。
3 ソフトウエアによるエンコード
x264encは、GStreamerでデフォルトで提供されるソフトウエアエンコーダーです。
参考:
https://gstreamer.freedesktop.org/documentation/x264/index.html?gi-language=c
x264encを使用した場合のコマンドは以下のようになります。
$ gst-launch-1.0 -v v4l2src ! videoconvert ! video/x-raw,format=I420,width=640,height=480,framerate=30/1 ! x264enc bframes=0 key-int-max=45 bitrate=500 tune=zerolatency ! video/x-h264,stream-format=avc,alignment=au ! kvssink stream-name=test-stream
CPUの負荷は、結構上がっている事が分かります。
$ vmstat 3 100 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 3710104 19236 113028 0 0 0 0 36 46 0 0 100 0 0 0 0 0 3710104 19236 113028 0 0 0 0 29 36 0 0 100 0 0 0 0 0 3710072 19236 113028 0 0 0 5 38 46 0 0 100 0 0 2 0 0 3693624 19912 124376 0 0 3823 313 429 649 2 2 93 3 0 0 0 0 3684184 19908 125020 0 0 228 15 1544 1969 23 2 75 0 0 0 0 0 3684208 19908 125020 0 0 0 12 1955 2658 35 1 64 0 0 0 0 0 3684144 19908 125020 0 0 0 0 1826 2519 33 2 65 0 0 0 0 0 3684112 19908 125020 0 0 0 0 1874 2723 35 1 64 0 0 0 0 0 3684080 19908 125020 0 0 0 0 1885 2779 34 1 65 0 0
この方法では、ちょっと古いRaspberry Piなどでは、安定した送信は、無理があるかも知れません。
4 ハードウエアによるエンコード
omxh264encは、RaspberryPiに実装されているハードウエアエンコーダーを使用するエレメントです。
omxが利用可能かどうかは、以下のように確認することが出来ます。
$ gst-inspect-1.0 | grep omx libav: avenc_h264_omx: libav OpenMAX IL H.264 video encoder encoder omx: omxhdmiaudiosink: OpenMAX HDMI Audio Sink omx: omxanalogaudiosink: OpenMAX Analog Audio Sink omx: omxh264enc: OpenMAX H.264 Video Encoder omx: omxvc1dec: OpenMAX WMV Video Decoder omx: omxmjpegdec: OpenMAX MJPEG Video Decoder omx: omxvp8dec: OpenMAX VP8 Video Decoder omx: omxtheoradec: OpenMAX Theora Video Decoder omx: omxh264dec: OpenMAX H.264 Video Decoder omx: omxh263dec: OpenMAX H.263 Video Decoder omx: omxmpeg4videodec: OpenMAX MPEG4 Video Decoder omx: omxmpeg2videodec: OpenMAX MPEG2 Video Decoder
使用する場合のコマンドは以下のとおりです。
$ gst-launch-1.0 -v v4l2src ! videoconvert ! video/x-raw,format=I420,width=640,height=480,framerate=30/1 ! omxh264enc periodicty-idr=45 inline-header=FALSE ! h264parse ! video/x-h264,stream-format=avc,alignment=au ! kvssink stream-name=test-stream
CPUの負荷は、殆ど上がっておらず、安定した送信が可能です。
$ vmstat 3 100 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 3696132 19924 126356 0 0 0 0 24 28 0 0 100 0 0 0 0 0 3696132 19928 126352 0 0 0 4 31 42 0 0 100 0 0 0 0 0 3696132 19928 126352 0 0 0 0 24 29 0 0 100 0 0 1 0 0 3691244 19928 126356 0 0 0 0 517 748 1 1 98 0 0 0 0 0 3690660 19928 126356 0 0 0 0 1221 2016 1 2 98 0 0 0 0 0 3690660 19936 126356 0 0 0 4 978 1696 1 1 98 0 0
5 カメラによるエンコード
カメラによっては、h.264のエンコーダーが組み込まれているものがあります。
今回使用している、 「Raspberry Pi 公式カメラ V2」も、その一つで、各種のフォーマットに対応しており、H264も確認できます。
$ v4l2-ctl -d /dev/video0 --list-formats ioctl: VIDIOC_ENUM_FMT Type: Video Capture [0]: 'YU12' (Planar YUV 4:2:0) [1]: 'YUYV' (YUYV 4:2:2) [2]: 'RGB3' (24-bit RGB 8-8-8) [3]: 'JPEG' (JFIF JPEG, compressed) [4]: 'H264' (H.264, compressed) [5]: 'MJPG' (Motion-JPEG, compressed) [6]: 'YVYU' (YVYU 4:2:2) [7]: 'VYUY' (VYUY 4:2:2) [8]: 'UYVY' (UYVY 4:2:2) [9]: 'NV12' (Y/CbCr 4:2:0) [10]: 'BGR3' (24-bit BGR 8-8-8) [11]: 'YV12' (Planar YVU 4:2:0) [12]: 'NV21' (Y/CrCb 4:2:0) [13]: 'BGR4' (32-bit BGRA/X 8-8-8-8)
v4l2srcは、h.264の入力も処理できるので、下記のように使用することが可能です。
gst-launch-1.0 -e v4l2src ! video/x-h264, width=640, height=480, framerate=30/1 ! h264parse ! video/x-h264,stream-format=avc,alignment=au ! kvssink stream-name=test-stream
この場合も、CPUへの負荷は殆どないため、安定した送信が可能です。
$ vmstat 3 100 procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- r b swpd free buff cache si so bi bo in cs us sy id wa st 0 0 0 3488288 29232 215692 0 0 17 1 58 75 1 0 99 0 0 0 0 0 3493172 29232 215692 0 0 0 0 132 126 0 0 100 0 0 0 0 0 3493172 29240 215692 0 0 0 12 83 100 0 0 100 0 0 0 0 0 3493172 29240 215692 0 0 0 0 41 47 0 0 100 0 0 0 0 0 3487656 29248 215692 0 0 0 11 1037 1082 2 2 96 0 0 0 0 0 3487624 29248 215692 0 0 0 1 1350 1285 0 1 99 0 0 0 0 0 3487576 29248 215692 0 0 0 0 1848 1826 1 1 98 0 0 1 0 0 3487448 29248 215692 0 0 0 0 1159 1179 1 1 98 0 0 0 0 0 3487352 29248 215692 0 0 0 0 1398 1229 1 1 98 0 0
6 その他
(1) カメラのモード
h.264のエンコードを使用するかどうかなど、カメラのモードは、GStreamer側から変更されます。 v4l2-ctl -allで、カメラの状態を確認出来ますが、Raspiのハードウエアエンコードを使用した直後に出力です。
$ v4l2-ctl --all (略) Format Video Capture: Width/Height : 640/480 Pixel Format : 'YU12' (Planar YUV 4:2:0) Field : None Bytes per Line : 640 Size Image : 460800 Colorspace : SMPTE 170M Transfer Function : Default (maps to Rec. 709) YCbCr/HSV Encoding: Default (maps to ITU-R 601) Quantization : Default (maps to Limited Range) (略)
そして、カメラのエンコードを使用した直後です。
$ v4l2-ctl --all (略) Video input : 0 (Camera 0: ok) Format Video Capture: Width/Height : 640/480 Pixel Format : 'H264' (H.264) Field : None Bytes per Line : 0 Size Image : 307200 Colorspace : SMPTE 170M Transfer Function : Default (maps to Rec. 709) YCbCr/HSV Encoding: Default (maps to ITU-R 601) Quantization : Default (maps to Full Range) Flags : (略)
以下のように、v4l2-ctlでモード変更が可能ですが、GStreamerを使用する場合、必要ないと言うことになります。
$ v4l2-ctl --device /dev/video0 --set-fmt-video=width=1280,height=960,pixelformat=1
(2) h.264をソース元にした場合の確認
ソース元からh.264を正常に受け取れているかどうかの切り分けには、下記のようなコマンドが有効かも知れません。
gst-launch-1.0 -e v4l2src device=/dev/video0 ! video/x-h264, width=640, height=488, framerate=30/1 ! avdec_h264 ! xvimagesink sync=false
(3) uvch264srcは諦めました
h.264の入力が、uvch264srcというエレメントで可能だという情報が有ったのですが、今回は、こちらはうまく動作させることが出来ませんでした。
何か必要な処置などがあれば、是非、教えてほしいです。
$ gst-launch-1.0 -v uvch264src device=/dev/video0 ! h264parse ! video/x-h264,stream-format=avc,alignment=au ! kvssink stream-name=test-stream ERROR: from element /GstPipeline:pipeline0/GstUvcH264Src:uvch264src0: Device is not a valid UVC H264 camera
(4) Logicool(logitech) C920
ネット上では、C920からh.264で取得している記事が多数公開されているのですが、残念ながら、最近のものには、実装されていないようです。
手元のC920の出力です。
$ v4l2-ctl -d /dev/video0 --list-formats ioctl: VIDIOC_ENUM_FMT Type: Video Capture [0]: 'YUYV' (YUYV 4:2:2) [1]: 'MJPG' (Motion-JPEG, compressed)
logitechのページで、以下のアナウンスを確認することができます。
The result of freeing up in-camera resources and instead focusing on delivering better image quality, have been born out in three of Logitech’s most popular webcams, the C920, C922 and BRIO.
7 最後に
今回は、Kinesis Video Streamsに送信する場合に必要な、h.264のエンコードについて、確認してみました。 安定した送信のために、ハードウエアによるエンコードをうまく利用する必要があるでしょう。(すいません、当たり前の話ですよね・・・)